import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;

public class Tokenizer {
	private static TokenList TOKEN_LIST;
	private static boolean stop_tokenizing;

	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		String line = null;
		BufferedReader reader = null;
		Tokenizer tokenizer = new Tokenizer();
		boolean repeat = true;
		
		while (repeat) {
			// Ask user for input file name
			System.out.println("Please enter the name of the input file: ");
			String file = input.next();

			// Load file to file reader
			try {
				reader = new BufferedReader(new FileReader(file));
			} catch (FileNotFoundException e) {}

			// Read in lines from input one at a time and tokenize
			try {
				while ((line = reader.readLine()) != null && !stop_tokenizing) {
					tokenizer.tokenizeLine(line);
				}

				// Print EOF token if no errors
				if (!stop_tokenizing) {
					System.out.println(33);
					
					// Ask user if they want to tokenize another file
					System.out.println("Tokenize another file? [Y/N]");
					String answer = input.next().toUpperCase();
					
					if (answer.equals("N")) {
						repeat = false;
					}
				}
				else {
					repeat = false;
					System.out.println("**Tokenizer Terminated**");
				}
			} catch (IOException e) {}
		}
    }
	
	
	public Tokenizer () {
		this.TOKEN_LIST = new TokenList();
		this.stop_tokenizing = false;
	}
	
	public void tokenizeLine (String line) {
		int i = 0;
		
		// Replace all white space by ' ' and split into separate tokens
		line = line.replaceAll("\\s+", Character.toString(' '));
		String[] tokens = line.split(" ");
		
		// Call getTokens to find tokens within each split in the line
		while (i < tokens.length && !stop_tokenizing) {
			
			// Check to make sure current array is not "", and get tokens for current string
			if (!tokens[i].equals("")) {
				getToken(tokens[i]);
				i++;
			}
			else {
				i++;
			}
		}
	}

	public void getToken(String token) {
		if (!stop_tokenizing) {
			
			// Check first character of string to determine which getToken method to call
			if (isSymbol(token.charAt(0))) {
				getSymbolToken(token);
			}
			else if (Character.isDigit(token.charAt(0))) {
				getDigitToken(token);
			}
			else if (Character.isLetter(token.charAt(0))) {
				if(Character.isUpperCase(token.charAt(0))) {
					getIdentifierToken(token);
				}
				else {
					getReservedWordToken(token);
				}
			}
			
			// If first character does not a valid symbol, digit, or letter, print an error
			else {
				System.out.println("ERROR: \"" + token.charAt(0) + "\" is not a valid CORE token");
				stop_tokenizing = true;
				if (token.length() > 1) {
					getToken(token.substring(1)); 
				}
			}
		}
	}
	
	public void getSymbolToken(String token) {
		
		// Check to see if the symbol is a special case that can be followed by another symbol
		if (isSpecialCase(token.charAt(0))) {
			String tok_string = "";
			String remaining_string = "";
			boolean error = false;
			
			// Check characters that can be followed by '=' and output tokens appropriately
			if (token.charAt(0) == '=' || token.charAt(0) == '!' || token.charAt(0) == '<' || token.charAt(0) == '>') {
				if (token.length() > 1) {
					if (token.charAt(1) == '=') {
						
						// Check length of current string and set remaining string to be tokenized if necessary
						if (token.length() > 2) {
							tok_string = token.substring(0,2);
							remaining_string = token.substring(2);
						}
						else {
							tok_string = token.substring(0);
						}
					}
					else {
						tok_string = Character.toString(token.charAt(0));
						remaining_string = token.substring(1);
					}
				}
				else {
					tok_string = Character.toString(token.charAt(0));
				}
			}
			// Check if required '|' follows, if not print error
			else if (token.charAt(0) == '|') {
				if (token.length() > 1) {
					if (token.charAt(1) == '|') {
						if (token.length() > 2) {
							tok_string = token.substring(0,2);
							remaining_string = token.substring(2);
						}
						else {
							tok_string = token.substring(0);
						}
					}
					else {
						error = true;
						remaining_string = token.substring(1);
					}
				}
				else {
					error = true;
				}
			}
			// Check if required '&' follows, if not print error
			else if (token.charAt(0) == '&') {
				if (token.length() > 1) {
					if (token.charAt(1) == '&') {
						if (token.length() > 2) {
							tok_string = token.substring(0,2);
							remaining_string = token.substring(2);
						}
						else {
							tok_string = token.substring(0);
						}
					}
					else {
						error = true;
						tok_string = token.substring(0,1);
						remaining_string = token.substring(1);
					}
				}
				else {
					error = true;
					tok_string = token.substring(0);
				}
			}
			
			// Output token
			if (!error) {
				System.out.println(TOKEN_LIST.getTokenNumber(tok_string));
			}
			else {
				System.out.println("ERROR: \"" + tok_string + "\" is not a valid symbol");
				stop_tokenizing = true;
			}
			
			// Call getToken if there are any characters remaining in string
			if (remaining_string.length() > 0) {
				getToken(remaining_string);
			}
		}
		else {
			String tok_string = Character.toString(token.charAt(0));
			
			// Output token 
			System.out.println(TOKEN_LIST.getTokenNumber(tok_string));
			
			// Check if there is anything remaining in current string and continue tokenizing
			if (token.length() > 1) {
				getToken(token.substring(1));
			}
		}
	}
	
	public void getDigitToken (String token) {
		int i = 0;
		
		// Iterate through string until current character is no longer a digit
		while (i < token.length() && Character.isDigit(token.charAt(i))) {
			i++;
		}
		
		// Output token
		System.out.println(31);

		// If there are more characters in the string, call getToken on the remaining string
		if (i < token.length()) {
			getToken(token.substring(i));
		}
	}
	
	public void getIdentifierToken (String token) {
		int i = 0;
		
		// Iterate through characters until the current character is not uppercase
		while (i < token.length() && Character.isUpperCase(token.charAt(i))) {
			i++;
		}
		
		// Iterate through remainder of string to see if identifier contains digits
		if (i < token.length() && Character.isDigit(token.charAt(i))) {
			while (i < token.length() && Character.isDigit(token.charAt(i))) {
				i++;
			}
			System.out.println(32);
		}
		else {
			System.out.println(32);
		}
		
		// If characters remain in string, call getToken on remainder
		if (i < token.length()) {
			getToken(token.substring(i));
		}
	}
	
	public void getReservedWordToken (String token) {
		int i = 0;
		String tok_string = null;
		
		// Iterate through each character until a lower case character is not found
		while (i < token.length() && Character.isLowerCase(token.charAt(i))) {
			i++;
		}
		tok_string = token.substring(0, i);
		
		// Check to see if token is a valid reserved word and print the token if it is
		if (TOKEN_LIST.getTokenNumber(tok_string) != 0) {
			System.out.println(TOKEN_LIST.getTokenNumber(tok_string));
		}
		else {
			System.out.println("ERROR: \"" + tok_string + "\" is not a valid reserved word");
			stop_tokenizing = true;
		}
		
		// Check if there are remaining characters in the current string and call getToken if there are
		if (token.length() > i) {
			getToken(token.substring(i));
		}
		
	}
	
	public boolean isSymbol(char c) {
		boolean result = false;
		if (c == ';' || c == ',' || c == '=' || c == '!' || c == '[' || c == ']' || c == '&' || c == '|' || c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '<' || c == '>') {
			result = true;
		}
		return result;
	}
	
	public boolean isSpecialCase(char c) {
		boolean result = false;
		if (c == '=' || c == '|' || c == '&' || c == '!' || c == '<' || c == '>') {
			result = true;
		}
		return result;
	}
}
